package suncertify.view.client;

import suncertify.service.Service;
import suncertify.service.ServiceEvent;
import suncertify.view.SwingUtils;
import suncertify.view.AsyncActionListener;
import suncertify.view.SCButton;
import suncertify.util.Notification;
import suncertify.util.Messages;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.Observer;
import java.util.Observable;

/**
 * RowDialog is swing dialog for editing/creating records
 */
public class RowDialog extends JDialog implements Observer, ActionListener {
    private static final Messages msg = Messages.getInstance();
    private final Service service;
    private JLabel[] labels;
    private JTextField[] textFields;
    private JButton updateButton;
    private JButton saveButton;
    private JButton findButton;
    private JButton cancelButton;
    private JFrame parent;
    private boolean locked = false;
    private Mode mode;


    private enum Mode {
        CREATE, EDIT, FIND
    }
    /**
     * constructor
     * @param service data service
     * @param parent parent frame
     */
    public RowDialog(Service service, JFrame parent) {
        super(parent, msg.get("ui.client.editor.title"), true);
        this.parent = parent;
        this.service = service;
        this.service.addObserver(this);
    }

    public void actionPerformed(ActionEvent e) {
        switch (mode) {
            case EDIT:
                updateButton.doClick();
                break;
            case FIND:
                findButton.doClick();
                break;
            case CREATE:
                saveButton.doClick();
        }
    }


    private void initComponents() {
        int count = this.service.getColumnCount();
        labels = new JLabel[count];
        textFields = new JTextField[count];
        for (int i = 0; i < count; ++i) {
            labels[i] = new JLabel(service.getColumnName(i));
            textFields[i] = new JTextField();
            textFields[i].addActionListener(this);
        }
        this.updateButton = new SCButton(msg.get("ui.client.editor.button.update"));
        this.updateButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent actionEvent) {
                String[] data = new String[textFields.length];
                for (int i = 0; i < data.length; ++i) {
                    data[i] = textFields[i].getText();
                }
                service.update(data);
            }
        });
        this.saveButton = new SCButton(msg.get("ui.client.editor.button.create"));
        this.saveButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent actionEvent) {
                String[] data = new String[textFields.length];
                for (int i = 0; i < data.length; ++i) {
                    data[i] = textFields[i].getText();
                }
                service.add(data);
            }
        });

        this.findButton = new SCButton(msg.get("ui.client.editor.button.find"));
        this.findButton.addActionListener(new AsyncActionListener() {
            public void doAsync(ActionEvent event) {
                String[] criteria = new String[textFields.length];
                for (int i = 0; i < textFields.length; ++i) {
                    criteria[i] = textFields[i].getText();
                }
                service.search(criteria);
            }
        });

        this.cancelButton = new SCButton(msg.get("ui.client.editor.button.cancel"));
        this.cancelButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent actionEvent) {
                service.unlock();
                setVisible(false);
            }
        });
        JPanel contentPanel = new JPanel();
        contentPanel.setDoubleBuffered(true);
        GridBagLayout gbl = new GridBagLayout();
        GridBagConstraints gbc = new GridBagConstraints();

        contentPanel.setLayout(gbl);

        gbc.fill = GridBagConstraints.HORIZONTAL;
        gbc.insets = new Insets(5, 10, 5, 10);
        for (int i = 0; i < count; ++i) {
            gbc.weightx = 0;
            gbc.gridwidth = GridBagConstraints.RELATIVE;
            contentPanel.add(labels[i], gbc);
            gbc.weightx = 1;
            gbc.gridwidth = GridBagConstraints.REMAINDER;
            contentPanel.add(textFields[i], gbc);
        }

        JPanel buttonPanel = new JPanel();
        buttonPanel.add(updateButton);
        buttonPanel.add(saveButton);
        buttonPanel.add(findButton);
        buttonPanel.add(cancelButton);

        contentPanel.add(buttonPanel, gbc);
        this.setContentPane(contentPanel);
        this.setSize(400, 300);

        addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent windowEvent) {
                cancelButton.doClick();
            }
        });
        new WaitDialog(parent, service);
    }

    /**
     * init RowDialog in find mode
     */
    public void find() {
        this.mode = Mode.FIND;
        for (JTextField textField : textFields) {
            textField.setText("");
        }
        setTitle(msg.get("ui.client.editor.find.title"));
        SwingUtils.placeCenter(parent, this);
        saveButton.setVisible(false);
        updateButton.setVisible(false);
        findButton.setVisible(true);
        setVisible(true);
    }

    /**
     * init RowDialog in edit mode
     */
    public void edit() {
        this.mode = Mode.EDIT;
        setTitle(msg.get("ui.client.editor.edit.title"));
        new Thread(new Runnable() {
            public void run() {
                service.lock();
            }
        }).start();
        SwingUtils.placeCenter(parent, this);
        saveButton.setVisible(false);
        findButton.setVisible(false);
        updateButton.setVisible(true);
    }

    /**
     * init RowDialog in create new record mode
     */
    public void create() {
        this.mode = Mode.CREATE;
        for (JTextField textField : textFields) {
            textField.setText("");
        }
        setTitle(msg.get("ui.client.editor.create.title"));
        SwingUtils.placeCenter(parent, this);
        saveButton.setVisible(true);
        updateButton.setVisible(false);
        findButton.setVisible(false);
        setVisible(true);
    }

    /**
     * updates the current view componen state
     * @param observable event source
     * @param o event object sent to observers
     */
    public void update(Observable observable, Object o) {
        if (!(o instanceof Notification)) {
            return;
        }
        final Notification n = (Notification) o;
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                switch ((ServiceEvent) n.getEvent()) {
                    case INITED:
                        initComponents();
                        break;
                    case CREATING:
                        for (JTextField textField : textFields) {
                            textField.setEnabled(false);
                        }
                        break;
                    case CREATED:
                        for (JTextField textField : textFields) {
                            textField.setEnabled(true);
                        }
                        setVisible(false);
                        break;
                    case LOCKING:
                        locked = false;
                        break;
                    case LOCKED:
                        saveButton.setEnabled(true);
                        updateButton.setEnabled(true);
                        cancelButton.setEnabled(true);
                        service.refresh();
                        String[] data = service.read();
                        for (int i = 0; i < data.length; ++i) {
                            textFields[i].setText(data[i].trim());
                            textFields[i].setEnabled(false);
                        }
                        for(JTextField f : textFields) {
                            f.setEnabled(true);
                        }
                        locked = true;
                        setVisible(true);
                        break;
                    case LOCK_CANCELLED:
                        locked = false;
                        setVisible(false);
                        break;
                    case FINDING:
                        findButton.setEnabled(false);
                        break;
                    case FOUND:
                        findButton.setEnabled(true);
                        setVisible(false);
                        break;
                    case UPDATING:
                        updateButton.setEnabled(false);
                        break;
                    case UPDATED:
                        service.unlock();
                        updateButton.setEnabled(false);
                        break;
                    case UNLOCKED:
                        locked = false;
                        setVisible(false);
                        break;
                    case ERROR:
                        if (locked) {
                            service.unlock();
                        } else {
                            setVisible(false);
                        }
                        break;
                }
            }
        });
    }
}
